; *******************************************************************
;   log4ahk.ahk
;   This is a test in the web browser
;   Extension for GUi
; *******************************************************************

; -------------------------------------------------------------------
;   log4ahk_level
; -------------------------------------------------------------------

class log4ahk_level
{
  OFF   := 2147483647
  FATAL := 50000
  ERROR := 40000
  WARN  := 30000
  INFO  := 20000
  DEBUG := 10000
  TRACE := 5000
  ALL   := -2147483647
  
  level := 10000
  levelStr := "DEBUG"
  
  __New(levelStr = "DEBUG")
  {
    this.level    := this.LevelStrToInt(levelStr)
    this.levelStr := levelStr
  }
  
  LevelStrToInt(levelStr)
  {
    lm := {}
    lm.OFF   := this.OFF 
    lm.FATAL := this.FATAL 
    lm.ERROR := this.ERROR 
    lm.WARN  := this.WARN 
    lm.INFO  := this.INFO 
    lm.DEBUG := this.DEBUG 
    lm.TRACE := this.TRACE 
    lm.ALL   := this.ALL 
    return lm[levelStr]
  }
  
  LevelIntToStr(levelInt)
  {
    lm := {}
    lm[this.OFF]   := "OFF" 
    lm[this.FATAL] := "FATAL" 
    lm[this.ERROR] := "ERROR" 
    lm[this.WARN]  := "WARN" 
    lm[this.INFO]  := "INFO" 
    lm[this.DEBUG] := "DEBUG" 
    lm[this.TRACE] := "TRACE" 
    lm[this.ALL]   := "ALL" 
    return lm[levelInt]
  }
  
  isGreaterOrEqual(other)
  {
    return this.level >= other.level
  }
}

; -------------------------------------------------------------------
;   log4ahk_event
; -------------------------------------------------------------------

class log4ahk_event
{
  time     := A_Now 
  logger   := ""
  level    := ""
  message  := ""
  
  __New(logger, level, message)
  {
    this.logger  := logger
    this.level   := level
    this.message := message
  }
}

; -------------------------------------------------------------------
;   log4ahk_appender
; -------------------------------------------------------------------

class log4ahk_appender
{
  closed         := false
  filter         := ""
  layout         := ""
  name           := ""
  threshold      := ""
  requiresLayout := true
  
  __New(name = "")
  {
    this.name  := name
    if (this.requiresLayout)
    {
      this.layout := new log4ahk_layout
    }
  }

  doAppend(event)
  {
    if (this.closed)
    {
      return
    }
    if (this.isAsSevereAsThreshold(event.level))
    {
      return
    }
    this.append(event)
  }

  append(event)
  {
    this.text .= this.layout.format(event) . "`n"
  }
  
  isAsSevereAsThreshold(level)
  {
    if (this.threshold == "")
    {
      return false
    }
    return level.isGreaterOrEqual(this.threshold)
  }  
}

; -------------------------------------------------------------------
;   log4ahk_appender_file
; -------------------------------------------------------------------

class log4ahk_appender_file extends log4ahk_appender
{
  locking := true
  file    := ""
  fp      := ""
  
  __New(name = "")
  {
    base.__New(name)
  }

  openFile()
  {
    this.fp := FileOpen(this.file,"a")
  }
  
  write(s)
  {
    if (!IsObject(this.fp))
    {
      this.OpenFile()
    }
    this.fp.WriteLine(s)
    this.fp.read(0)
  }
  
  append(event)
  {
    this.write(this.layout.format(event))
  }
  
  close()
  {
    this.fp.close()
    this.fp := "" 
  }
}

; -------------------------------------------------------------------
;   log4ahk_loggers
; -------------------------------------------------------------------

class log4ahk_loggers
{
}

; -------------------------------------------------------------------
;   log4ahk_layout
; -------------------------------------------------------------------

class log4ahk_layout
{
  format(event)
  {
    level    := new log4ahk_level
    levelStr := level.LevelIntToStr(event.level)
    time     := event.time
    tf       := "d. MMMM yyyy, HH:mm:ss"
    FormatTime ftime, %time%, %tf%
    msg := "LOG: " . ftime . " " . levelStr . " " . event.message
    return msg
  }
}

; -------------------------------------------------------------------
;   log4ahk_logger
; -------------------------------------------------------------------

class log4ahk_logger 
{
  static LevelTrace    := 12000
  static LevelDebug    := 14000
  static LevelInfo     := 16000
  static LevelWarn     := 18000
  static LevelError    := 20000
  static LevelCritical := 22000
  static LevelFatal    := 24000
	
  level     := ""
  name      := ""
  appenders := []

  __New(name = "")
  {
    this.name  := name
    this.level := this.LevelInfo
    appender := new log4ahk_appender
    this.appenders.Insert(appender)
  }
  
  trace(message)
  {
    this.log(this.LevelTrace, message)
  }     
  
  debug(message)
  {
    this.log(this.LevelDebug, message)
  } 
  
  info(message)
  {
    this.log(this.LevelInfo, message)
  }
  
  warn(message)
  {
    this.log(this.LevelWarn, message)
  }
  
  error(message)
  {
    this.log(this.LevelError, message)
  }
  
  fatal(message)
  {
    this.log(this.LevelFatal, message)
  }

  log(level, message) 
  {
    if (level >= this.level)
    {
      ev := new log4ahk_event(this, level, message)
      this.callAppenders(ev)
    }
  }
  
  callAppenders(event)
  {
    for k, appender in this.appenders
    {
      appender.doAppend(event)
    }
  }
  
  ; ******************************************
  ; *** Configuration methods              ***
  ; ******************************************
    
  addAppender(appender)
  {
    appenderName := appender.name
    this.appenders[appenderName] := appender
  }
  
  removeAllAppenders()
  {
    this.appenders := {}
  } 
  
  removeAppender(appender)
  {
    appenderName := appender.name
    this.appenders.Remove(appenderName)
  }
  
  isAttached(appender)
  {
    appenderName := appender.name
    return this.appenders.HasKey(appenderName)
  }
  
  
  getLogger(name) 
  {
    global log4ahk_cnfg
    if !IsObject(log4ahk_cnfg)
    {
      log4ahk_cnfg := new log4ahk
    }
    return log4ahk_cnfg.getLogger(name)
  }
  
}

; -------------------------------------------------------------------
;   log4ahk
; -------------------------------------------------------------------

class log4ahk
{
  appenders := []
   
  __New(name = "")
  {
    this.name  := name
    this.level := new log4ahk_level
    appender := new log4ahk_appender
    this.appenders.Insert(appender)
  }
 
  getLogger(name)
  {
    if (log4ahk_loggers.HasKey(name))
    {
      return log4ahk_loggers[name]
    }
    else
    {
      log := new log4ahk_logger
      log.name := name
      log4ahk_loggers.Insert(name, log)
      return log
    }
  }

  log(level, msg)
  {
    if (this.isEnabledFor(level))
    {
      ev := new log4ahk_event(this, level, msg)
      this.callAppenders(ev)
    }
  }

  trace(msg)
  {
    this.log(this.level.TRACE, msg)
  }

  debug(msg)
  {
    this.log(this.level.DEBUG, msg)
  }

  info(msg)
  {
    this.log(this.level.INFO, msg)
  }

  warn(msg)
  {
    this.log(this.level.WARN, msg)
  }

  error(msg)
  {
    this.log(this.level.ERROR, msg)
  }

  fatal(msg)
  {
    this.log(this.level.FATAL, msg)
  }
  
  callAppenders(event)
  {
    for k, v in this.appenders
    {
      v.doAppend(event)
    }
  }
}


